package cs342.project1.mathNotebook.expressions;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Properties;

/**
 * Creates expression objects
 * 
 * @author Jared Schlicht
 */
public class ExprFactory {
    private Properties properties;

    public ExprFactory() throws FileNotFoundException, IOException {
	this.properties = new Properties();
	this.properties.load(new FileInputStream("operator.properties"));
    }

    /**
     * Creates an expression object based on its operator
     * 
     * @param operator
     *            the operator (+, -, *, ^ etc)
     * @param params
     *            the parameters for this operator. There should be 1 parameter
     *            for usnary expressions and 2 for binary expressions
     * @return Expr object or null if an error occurred while constructing the
     *         expression
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     * @throws InstantiationException
     * @throws IllegalArgumentException
     * @throws ClassNotFoundException
     * @throws NoSuchMethodException
     * @throws SecurityException
     */
    public Expr createExpression(String operator, Object[] params)
	    throws IllegalArgumentException, InstantiationException,
	    IllegalAccessException, InvocationTargetException,
	    ClassNotFoundException, SecurityException, NoSuchMethodException {
	Class<?> c = Class.forName(this.properties.getProperty(operator));
	Class[] classParams = new Class[params.length];
	for (int i = 0; i < classParams.length; i++) {
	    classParams[i] = Expr.class;
	}

	Constructor constructor = c.getConstructor(classParams);
	return (Expr) constructor.newInstance(params);
    }

    /**
     * Determines the number of operands required for the specified operator
     * 
     * @param operator
     *            the operator to lookup the number of operands for
     * @return the number of operands for the operator
     * @author Jared Schlicht
     */
    public int operands(String operator) {
    	int temp = Integer.parseInt(this.properties.getProperty(operator
    			+ "operands"));
    	//System.out.println(temp);
	return temp;
    }

    /**
     * Determines the precedence level of the operator
     * 
     * @param operator
     *            the operator to lookup precedence for
     * @return the precedence level (as an integer). High precedence operators
     *         will return a higher integer value
     * @author Jared Schlicht
     */
    public int precedence(String operator) {
	return Integer.parseInt(this.properties.getProperty(operator
		+ "precedence"));
    }

    /**
     * Determines if this operator is left or right associative
     * 
     * @param the
     *            operator to determine associativity for
     * @return true if the operator is left associative, false if it is right
     *         associative
     * @author Jared Schlicht
     */
    public boolean isLeftAssociative(String operator) {
	return Boolean.parseBoolean(this.properties.getProperty(operator
		+ "leftAssoc"));
    }
}
